import com.pbking.util.eventHandling.EventBroadcaster;
import com.pbking.util.EasyXML;
import com.pbking.util.eventHandling.Event;
import mx.services.WebService;
import com.pbking.logging.Logger;
import com.pbking.util.Proxy;

/**
 * This is the base class for WebServiceConsumers.
 * It is not usable in and of itself.  It requires a config file
 * (default: flash_webservice_configuration.xml)
 * that is constructed:
 * code{
 * 	<config>
 * 		<serviceName>http://website.com/webservice.aspx</serviceName>
 * 		<serviceName2>http://website.com/webservice2.aspx</serviceName2>
 * 	</config>
 * }
 * Once that file has been parsed, all of the WebService instances are available via getService(name)
 * where "name" is the name of the node; such as "serviceName"
 * 
 * You usually wouldn' use getService, however.  Instead, you would extend this class and add on 
 * to it methods that would call services.  (Make sure to copy Singleton code to the extended class)
 * 
 * @author Jason Crist
 */
class com.pbking.web.WebserviceConsumer extends EventBroadcaster {

	// SINGLETON CODE //////////////////////////////////////
	//This should be copied into every class that
	//extends WebserviceConsumer.
	//Remember to change new WebserviceConsumer()
	//to new WhateverYourServiceConsumerIs()
	//Remember also to make your constructor private
	
	public static var instance;
	
	public static function getInstance()
	{
		if(instance == null)
			instance = new WebserviceConsumer();
			
		return instance;
	}
	
	////////////////////////////////////////////////////////
	
	// VARIABLES //////////

	private var services:Object;
	private var _isReady:Boolean;
	private var _configURI:String;

	// CONSTRUCTION //////////
	
	private function WebserviceConsumer() 
	{
		services = new Object();
	}

	// GETTERS and SETTERS //////////
	
	public function get isReady():Boolean
	{
		return this._isReady;
	}
	
	public function get configURI():String
	{
		return this._configURI;
	}

	// PUBLIC FUNCTIONS //////////
	
	/**
	 * 
	 */
	public function getService(serviceName:String):WebService{
		return services[serviceName];
	}
	
	// PRIVATE FUNCTIONS //////////
	
	private function addService(serviceName:String, serviceWSDL:String){
		Logger.debug("adding service: " + serviceName + ":" + serviceWSDL);
		var newService:WebService = new WebService(serviceWSDL);
		newService.onFault = Proxy.create(this, onServiceFault);
		newService.onLoad = Proxy.create(this, onServiceLoad);
		services[serviceName] = newService;
	}
	
	private function onServiceFault(fault:Object){
		Logger.warning("Couldn't load service!!", "WebserviceConsumer", "onServiceFault");
		Logger.warning(fault);
	}

	public function onServiceLoad(load:Object){
		Logger.finest("Service loaded!");
	}

	public function onSoapFault(fault:Object){
		Logger.warning("Error while making a SOAP call");
		Logger.warning(fault);
	}

	// CONFIGURATION
	
	private function loadConfig(configURI:String)
	{
		if(configURI == null)
			configURI = "flash_webservice_configuration.xml";
			
		this._configURI = configURI;
			
		var config:EasyXML = new EasyXML();
		
		config.addEventListener("onLoad", this, onConfig);
		config.addEventListener("onError", this, onConfigError);
		
		config.load(configURI);
	}
	
	private function onConfig(event:Event){
		var config:XMLNode = event.target;
		config = config.firstChild.firstChild;

		while(config != null){
			addService(config.nodeName, config.firstChild.nodeValue);
			config = config.nextSibling;
		}
		
		//that's all we have to do to start accepting calls
		_isReady = true;
		dispatch(new Event("onReady", this));
	}
	
	private function onConfigError(event:Event)
	{
		Logger.warning("There was a problem loading the webservice consumer config file: " + configURI, "WebserviceConsumer", "onConfigError");
	}
	
}